(define-module (api-utils)
  #:export (define-api-route))


(use-modules (web client)
             (web uri)
             (json)
             (ice-9 iconv))


(define-syntax variable-name->string
  (lambda (stx)
    (syntax-case stx ()
      ((_ id)
       (identifier? #'id)
       (datum->syntax #'id (symbol->string (syntax->datum #'id)))))))


(define-syntax define-api-route
  ;; https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods
  ;; All HTTP methods are literals.
  (syntax-rules (GET HEAD POST PUT DELETE CONNECT OPTIONS TRACE PATH)
    ;; for GET requests
    [(define-api-route route GET my-content-type)
     (define* (route docker-socket #:key (data #f))
       (call-with-values
           (lambda ()
             (http-get (variable-name->string route)
                         #:port docker-socket
                         #:version '(1 . 1)
                         #:keep-alive? #f
                         #:headers `((host . ("localhost" . #f))
                                     (content-type . (my-content-type (charset . "utf-8"))))
                         #:body (scm->json-string data)
                         #:decode-body? #t
                         #:streaming? #f))
         (lambda (response response-text)
           (let ([resp-text-as-string (bytevector->string response-text "utf-8")])
             (cons response resp-text-as-string)))))]
    ;; for POST requests
    [(define-api-route route POST my-content-type)
     (define* (route docker-socket #:key (data #f))
       (call-with-values
           (lambda ()
             (http-post (variable-name->string route)
                       #:port docker-socket
                       #:version '(1 . 1)
                       #:keep-alive? #f
                       #:headers `((host . ("localhost" . #f))
                                   (content-type . (my-content-type (charset . "utf-8"))))
                       #:body (scm->json-string data)
                       #:decode-body? #t
                       #:streaming? #f))
         (lambda (response response-text)
           (let ([resp-text-as-string (bytevector->string response-text "utf-8")])
             (cons response resp-text-as-string)))))]))
